package top.zhangjianyong.tools.indicator.strategy.impl;

import org.springframework.stereotype.Component;
import top.zhangjianyong.tools.entity.ETFData;
import top.zhangjianyong.tools.indicator.context.IndicatorContext;
import top.zhangjianyong.tools.indicator.model.TechnicalIndicatorResult;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

/**
 * 威廉指标（Williams %R）计算器
 * 窗口14
 *
 * @author zhangjianyong
 * @date 2024/01/01
 */
@Component
public class WilliamsRIndicator extends AbstractIndicator {

    private static final String INDICATOR_NAME = "WILLIAMSR";
    private static final int PERIOD = 14;

    @Override
    public String getName() {
        return INDICATOR_NAME;
    }

    @Override
    public int getMinDataSize() {
        return PERIOD;
    }

    @Override
    protected TechnicalIndicatorResult doCalculate(IndicatorContext context) {
        List<ETFData> dataList = context.getDataList();

        // 取最后PERIOD个数据点
        int startIndex = Math.max(0, dataList.size() - PERIOD);
        List<ETFData> subList = dataList.subList(startIndex, dataList.size());

        // 计算最高价和最低价
        BigDecimal highest = subList.stream()
            .map(ETFData::getValue)
            .max(BigDecimal::compareTo)
            .orElse(BigDecimal.ZERO);

        BigDecimal lowest = subList.stream()
            .map(ETFData::getValue)
            .min(BigDecimal::compareTo)
            .orElse(BigDecimal.ZERO);

        // 当前收盘价
        BigDecimal currentPrice = dataList.get(dataList.size() - 1).getValue();

        // 计算威廉指标
        // %R = (最高价 - 收盘价) / (最高价 - 最低价) * (-100)
        BigDecimal williamsR = BigDecimal.ZERO;
        BigDecimal range = highest.subtract(lowest);

        if (range.compareTo(BigDecimal.ZERO) != 0) {
            williamsR = highest.subtract(currentPrice)
                .divide(range, 4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal(-100));
        } else {
            williamsR = new BigDecimal(-50); // 如果最高价等于最低价，返回-50
        }

        // 限制在-100到0范围内
        if (williamsR.compareTo(new BigDecimal(-100)) < 0) {
            williamsR = new BigDecimal(-100);
        } else if (williamsR.compareTo(BigDecimal.ZERO) > 0) {
            williamsR = BigDecimal.ZERO;
        }

        TechnicalIndicatorResult result = TechnicalIndicatorResult.success(getName());
        result.addValue("williams_r", williamsR.setScale(2, RoundingMode.HALF_UP));
        result.addValue("williams_r_14", williamsR.setScale(2, RoundingMode.HALF_UP));

        return result;
    }
}

